package org.supereasymock;

import scala.collection.mutable.Queue
import org.easymock.EasyMock
import org.easymock.IExpectationSetters

object SuperEasyMock {   
    
    def expect(body: => Unit)(implicit context: SuperEasyMockContext): TestBlock = {
        new ExpectBlock(context).expect(body)
    }
    
    def createMock[T <: AnyRef](toMock: Class[T])(implicit context: SuperEasyMockContext): T = {
        context.create(toMock, EasyMock.createMock(_: Class[T]))
    }
    
    def createNiceMock[T <: AnyRef](toMock: Class[T])(implicit context: SuperEasyMockContext): T = {
        context.create(toMock, EasyMock.createNiceMock(_: Class[T]))
    }
    
    def createStrictMock[T <: AnyRef](toMock: Class[T])(implicit context: SuperEasyMockContext): T = {
        context.create(toMock, EasyMock.createStrictMock(_: Class[T]))
    }
    
    implicit def createExpectationSetters[T](value: T): IExpectationSetters[T] = {
        EasyMock.expect(value)
    }
    
    private[SuperEasyMock] class ExpectBlock(private val context: SuperEasyMockContext) {
        def expect(body: => Unit): TestBlock = {
            body
            new TestBlock(context)
        }
    }

    private[SuperEasyMock] class TestBlock(private val context: SuperEasyMockContext) {
        context.replayAll()
        
        def test(body: => Unit): VerifyBlock = {
            body
            new VerifyBlock(context)
        }
    }

    private[SuperEasyMock] class VerifyBlock(private val context: SuperEasyMockContext) {
        context.verifyAll()
        
        def verify(body: => Unit) = {
            body
            context.resetAll()
        }
    }
}

class SuperEasyMockContext {

    private val mocks = new Queue[AnyRef]
    
    private[supereasymock] def create[T <: AnyRef](toMock: Class[T], factory: Class[T] => T) = {
        val mock = factory(toMock)
        
        mocks += mock
        mock
    }
    
    private[supereasymock] def replayAll() {
        EasyMock.replay(mocks toArray)
    }
    
    private[supereasymock] def verifyAll() {
        EasyMock.verify(mocks toArray)
    }
    
    private[supereasymock] def resetAll() {
        EasyMock.reset(mocks toArray)
    }
}
